package com.qp.basics.estivate.transaction;

import com.qp.basics.estivate.transaction.support.DefaultTransactionStatus;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public abstract class TransactionManager {

	private Log logger = LogFactory.getLog(getClass());

	public final TransactionStatus getTransaction(
			TransactionDefinition definition) {
		Object txObject = doGetTransaction();

		if (isExistingTransaction(txObject)) {
			handleExistingTransaction(definition, txObject);
		}

		try {
			doBegin(txObject, definition);
		} catch (Exception ex) {
			throw new TransactionException("无法开启事务", ex);
		}

		return new DefaultTransactionStatus(txObject, true,
				definition.isReadOnly());
	}

	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction) {
		// TODO
		throw new TransactionException("暂时不支持嵌套事务");
	}

	protected boolean isExistingTransaction(Object transaction) {
		return false;
	}

	protected abstract Object doGetTransaction();

	public void doBegin(Object txOBject, TransactionDefinition definition)
			throws Exception {

	}

	public final void rollback(TransactionStatus status) {
		if (status.isCompleted()) {
			throw new TransactionException("事务已经结束，不要重复调用");
		}
		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		processRollback(defStatus);
	}

	public final void commit(TransactionStatus status) {
		if (status.isCompleted()) {
			throw new TransactionException("事务已经结束，不要重复调用");
		}

		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		if (defStatus.isReadOnly()) {
			processRollback(defStatus);
			return;
		}

		processCommit(defStatus);
	}

	private void cleanupAfterCompletion(DefaultTransactionStatus status) {
		status.setCompleted();
		if (status.isNewTransaction()) {
			doCleanupAfterCompletion(status.getTransactionObject());
		}
	}

	private void processRollback(DefaultTransactionStatus status) {
		try {
			if (status.isNewTransaction()) {
				doRollback(status);
			} else if (status.hasTransaction()) {
				logger.debug("请在起始事务中执行rollback");
			} else {
				logger.debug("应该执行callback，但是没有事务存在");
			}
		} finally {
			cleanupAfterCompletion(status);
		}
	}

	private void processCommit(DefaultTransactionStatus status) {
		try {
			if (status.isNewTransaction()) {
				doCommit(status);
			} else if (status.hasTransaction()) {
				logger.debug("请在起始事务中执行commit");
			} else {
				logger.debug("应该执行commit，但是没有事务存在");
			}
		} finally {
			cleanupAfterCompletion(status);
		}

	}

	protected void doCleanupAfterCompletion(Object transactionObject) {
	}

	protected abstract void doRollback(DefaultTransactionStatus status);

	protected abstract void doCommit(DefaultTransactionStatus status);
}
